#include "./select_cmd.hpp"

#include <KDTree/KDTree.hpp>
#include <algorithm>

/* For geometry operations */
#include <geos/geom/Coordinate.h>
#include <geos/geom/Envelope.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/Point.h>

/* For indexing */
#include <geos/index/strtree/TemplateSTRtree.h>

/* For WKT read/write */
#include <geos/io/WKTReader.h>
#include <geos/io/WKTWriter.h>

namespace qbe::select {

template <typename T>
void query_geo_part(T geo, double x, double y, double w, double h, std::vector<layout::SelectQuad::Node>& part) {
  auto s_quad = layout::SelectQuad::create();

  auto add_part_center = [&](auto& center) {
    layout::SelectQuad::add_points(s_quad, qlib::Vec2dArray{center}, qlib::GeoPartType::Center);
  };

  auto add_part_points = [&](auto& points) {
    auto edges = qlib::get_edges(points);
    auto edges_mid = qlib::get_edges_mid(edges);
    layout::SelectQuad::add_points(s_quad, points, qlib::GeoPartType::Point);
    layout::SelectQuad::add_edges(s_quad, edges, qlib::GeoPartType::Edge);
    layout::SelectQuad::add_points(s_quad, edges_mid, qlib::GeoPartType::EdgeMid);
  };

  auto add_part_box = [&](auto& box_points) {
    auto box_edges = qlib::get_edges(box_points);
    auto box_edges_mid = qlib::get_edges_mid(box_edges);
    layout::SelectQuad::add_points(s_quad, box_edges_mid, qlib::GeoPartType::BoxEdgeMid);
  };

  auto add_part_fan = [&](auto& box_points) {
    auto box_edges = qlib::get_edges(box_points);
    auto box_edges_mid = qlib::get_edges_mid(box_edges);
    layout::SelectQuad::add_points(s_quad, box_edges_mid, qlib::GeoPartType::BoxEdgeMid);
  };

  // path
  if constexpr (std::is_same<T, qlib::Path::s_ptr>::value) {
    add_part_points(geo->spine.points);

    qlib::PolygonPtrArray polys;
    geo->to_polygons(false, qlib::Tag{0, 0}, polys);
    for (auto poly : polys) {
      add_part_points(qlib::connect_end(poly->points));
    }
  }
  if constexpr (std::is_same<T, qlib::Polygon::s_ptr>::value || std::is_same<T, qlib::ViewArea3D::s_ptr>::value) {
    auto box = geo->bounding_box();
    auto center = qlib::box_center(box);
    add_part_center(center);
    add_part_points(qlib::connect_end(geo->points));
  }
  if constexpr (std::is_same<T, qlib::Rectangle::s_ptr>::value || std::is_same<T, qlib::SectionArea3D::s_ptr>::value) {
    auto box = geo->bounding_box();
    auto center = qlib::box_center(box);
    add_part_center(center);
    add_part_points(qlib::connect_end(geo->to_polygon()->points));
  }
  // if constexpr (std::is_same<T, qlib::Circle::s_ptr>::value) {
  //   add_part_center(geo->center);
  //   add_part_box(connect_end(qlib::box_to_points(geo->bounding_box())));
  //   add_part_points(connect_end(geo->to_polygon()->points));
  // }
  if constexpr (std::is_same<T, qlib::Ellipse::s_ptr>::value) {
    add_part_center(geo->center);
    add_part_box(connect_end(geo->obb()));
    // add_part_points(connect_end(geo->to_polygon()->points));
  }
  if constexpr (std::is_same<T, qlib::Fan::s_ptr>::value) {
    auto points = geo->to_polygon()->points;
    auto center = points[0];
    auto arc_center = geo->get_arc_center();
    auto arc_start = points[1];
    auto arc_end = points[points.size() - 1];
    add_part_center(center);
    add_part_center(arc_center);
    add_part_points(qlib::Vec2dArray{center, arc_start});
    add_part_points(qlib::Vec2dArray{center, arc_end});
  }
  if constexpr (std::is_same<T, qlib::Label::s_ptr>::value || std::is_same<T, qlib::Pin::s_ptr>::value ||
                std::is_same<T, qlib::KeyPoint::s_ptr>::value || std::is_same<T, qlib::Text::s_ptr>::value) {
    add_part_center(geo->origin);
  }

  if constexpr (std::is_same<T, qlib::Ruler::s_ptr>::value) {
    add_part_points(qlib::Vec2dArray{geo->start, geo->end});
  }

  part = s_quad->query(quadtree::Box<double>(x, y, w, h));
}

template <typename T>
bool query_geo_part_try(const entt::registry& reg, entt::entity e, double x, double y, double w, double h,
                        std::vector<layout::SelectQuad::Node>& part) {
  auto geo_ptr = reg.try_get<T>(e);
  if (geo_ptr) {
    query_geo_part(*geo_ptr, x, y, w, h, part);
    return true;
  }
  return false;
}

template <typename... Args>
bool query_geo_part_multi(const entt::registry& reg, entt::entity e, double x, double y, double w, double h,
                          std::vector<layout::SelectQuad::Node>& part, const std::tuple<Args...>&) {
  return (query_geo_part_try<Args>(reg, e, x, y, w, h, part) || ...);
}

geos::geom::CoordinateSequence get_coordseq(const qlib::Vec2dArray& points) {
  std::vector<geos::geom::Coordinate> coords;
  for (auto& p : points) {
    coords.push_back(geos::geom::Coordinate{p.x, p.y});
  }
  geos::geom::CoordinateSequence coord_seq;
  coord_seq.setPoints(coords);
  return coord_seq;
};

bool SelectCmd::projectPointToSegment(const qlib::Vec2d& A, const qlib::Vec2d& B, const qlib::Vec2d& P, qlib::Vec2d& Q) {
  qlib::Vec2d AB = {B.x - A.x, B.y - A.y};  // 向量 AB
  qlib::Vec2d AP = {P.x - A.x, P.y - A.y};  // 向量 AP

  // 计算点积和向量 AB 的模长平方
  double dotProduct = AB.x * AP.x + AB.y * AP.y;
  double squaredLengthAB = AB.x * AB.x + AB.y * AB.y;

  // 计算投影系数 t
  double t = dotProduct / squaredLengthAB;

  // 如果 t 在 [0, 1] 之间，则投影点在线段上
  if (t >= 0 && t <= 1) {
    Q = {A.x + t * AB.x, A.y + t * AB.y};
    return true;
  }
  return false;
}

// 点是否在矩形内
bool SelectCmd::is_point_in_rect(qlib::Vec2d p, const qlib::Vec2dArray& box) {
  return (p.x >= box[0].x && p.x <= box[1].x && p.y >= box[0].y && p.y <= box[1].y);
}

// 点集是否在矩形内
bool SelectCmd::is_points_in_rect(qlib::Vec2dArray& ps, const qlib::Vec2dArray& box) {
  for (auto& p : ps) {
    bool is_in = (p.x >= box[0].x && p.x <= box[1].x && p.y >= box[0].y && p.y <= box[1].y);
    if (!is_in)
      return false;
  }
  return true;
}

// 是否包含
bool SelectCmd::is_rect_contained(const Rect& a, const Rect& b) {
  return (a.x <= b.x) && (a.y <= b.y) && (a.x + a.width >= b.x + b.width) && (a.y + a.height >= b.y + b.height);
};

// 计算距离函数
double cacl_distance(qlib::Vec2d point, qlib::Vec2dArray edge) {
  auto gf = geos::geom::GeometryFactory::create();
  auto mouse_point = gf->createPoint(geos::geom::Coordinate{point.x, point.y});

  std::vector<geos::geom::Coordinate> coords;
  for (auto& p : edge) {
    coords.push_back(geos::geom::Coordinate{p.x, p.y});
  }
  std::unique_ptr<geos::geom::CoordinateSequence> coord_seq = std::make_unique<geos::geom::CoordinateSequence>();
  coord_seq->setPoints(coords);

  auto g_ls = gf->createLineString(std::move(coord_seq));
  auto d = mouse_point->distance(g_ls.get());

  return d;
};

// 是否包含
// bool SelectCmd::is_rect_contained(const qlib::Vec2dArray& a, const qlib::Vec2dArray& b) {
//   // a_x = a[0].x;
//   // a_y = a[0].y;
//   a_w = a[1].x - a[0].x;
//   a_h = a[1].y - a[0].y;

//   b_w = b[1].x - b[0].x;
//   b_h = b[1].y - b[0].y;
//   return (a[0].x <= b[0].x) && (a[0].y <= b[0].y) && (a[0].x + a_w >= b[0].x + b_w) && (a[0].y + a_h >= b[0].y + b_h);
// }

// // 线段与矩形是否相交
// bool is_intersect(const qlib::Vec2dArray geo1, const qlib::Vec2dArray& geo2) {
//   auto gf = geos::geom::GeometryFactory::create();
//   auto g_ls = gf->createLineString(to_coord(geo1));
//   auto g_box = gf->createLineString(to_coord(geo2));
//   return g_ls->intersect(g_box.get());
// }

vsg::mat4 SelectCmd::get_ref_mat(qlib::Reference::s_ptr ref) {
  float ca = std::cos(ref->rotation);
  float sa = std::sin(ref->rotation);
  float sx = 1.0 * ref->magnification;
  float sy = (ref->x_reflection ? -1.0 : 1.0) * ref->magnification;
  float tx = ref->origin.x;
  float ty = ref->origin.y;
  auto s_mat = vsg::mat4{
      sx, 0,  0, 0,  //
      0,  sy, 0, 0,  //
      0,  0,  1, 0,  //
      0,  0,  0, 1   //
  };
  auto r_mat = vsg::mat4{
      ca,  sa, 0, 0,  //
      -sa, ca, 0, 0,  //
      0,   0,  1, 0,  //
      0,   0,  0, 1,  //
  };
  auto t_mat = vsg::mat4{
      1,  0,  0, 0,  //
      0,  1,  0, 0,  //
      0,  0,  1, 0,  //
      tx, ty, 0, 1,  //
  };
  auto transform_mat = t_mat * r_mat * s_mat;
  return transform_mat;
}

qlib::Vec2d SelectCmd::tran_to_cell_point(qlib::Vec2d p, qlib::Reference::s_ptr ref) {
  auto transform_mat = get_ref_mat(ref);
  auto pos = transform_mat * vsg::vec4(p.x, p.y, 0, 1);
  return qlib::Vec2d{pos.x, pos.y};
}

qlib::Vec2d SelectCmd::tran_to_ref_point(qlib::Vec2d p, qlib::Reference::s_ptr ref) {
  // auto transform = [&](auto magnification, auto x_reflection, auto rotation, auto origin) {
  //   double ca = cos(rotation);
  //   double sa = sin(rotation);
  //   auto q = p * magnification;
  //   if (x_reflection)
  //     q.y = -q.y;
  //   p->x = q.x * ca - q.y * sa + origin.x;
  //   p->y = q.x * sa + q.y * ca + origin.y;
  // };

  // transform(ref->magnification, ref->x_reflection, ref->rotation, ref->origin);
  // return p;

  auto transform_mat = get_ref_mat(ref);
  // 获取逆矩阵
  vsg::mat4 in_mat = vsg::inverse_4x4(transform_mat);
  // 通过逆矩阵转换点
  auto pos = in_mat * vsg::vec4(p.x, p.y, 0, 1);
  return qlib::Vec2d{pos.x, pos.y};
}

void SelectCmd::add_hover(const entt::entity& e) {
  auto tag = cell->reg.try_get<qlib::Tag>(e);
  if (tag) {
    // 过滤隐藏图层
    if (!layer_manager.is_hide(*tag)) {
      cell->reg.emplace_or_replace<HoverTag>(e, HoverTag{});
    }
  }
  auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(e);
  if (ref)
    cell->reg.emplace_or_replace<HoverTag>(e, HoverTag{});
  m_hover_render = true;
};

void SelectCmd::add_hovers(const EntityArray& e_arr) {
  for (auto& e : e_arr) {
    add_hover(e);
  }
  m_hover_render = true;
};

void SelectCmd::add_select(const entt::entity& e, bool is_order) {
  auto tag = cell->reg.try_get<qlib::Tag>(e);
  if (tag) {
    // 过滤隐藏图层
    if (!layer_manager.is_hide(*tag)) {
      cell->reg.emplace_or_replace<SelectTag>(e, SelectTag{});
      if (is_order)
        m_select_orders[e] = true;
    }
  }
  auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(e);
  if (ref) {
    cell->reg.emplace_or_replace<SelectTag>(e, SelectTag{});
    m_select_orders[e] = true;
  }
  m_select_render = true;
};

void SelectCmd::add_selects(const EntityArray& e_arr, bool is_order) {
  for (auto& e : e_arr) {
    add_select(e, is_order);
  }
  m_select_render = true;
};

void SelectCmd::remove_select(const entt::entity& e, bool is_order) {
  auto tag = cell->reg.try_get<qlib::Tag>(e);
  if (tag) {
    // 过滤隐藏图层
    if (!layer_manager.is_hide(*tag)) {
      cell->reg.remove<SelectTag>(e);
      // if (is_order)
      //   m_select_orders.erase(e);
    }
  }
  auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(e);
  if (ref) {
    cell->reg.remove<SelectTag>(e);
  }
  m_select_render = true;
};

// 删除选择
void SelectCmd::remove_selects(const EntityArray& e_arr, bool is_order) {
  for (auto& e : e_arr) {
    remove_select(e, is_order);
  }
  m_select_render = true;
};

void SelectCmd::clear_select() {
  // 清除预选标记
  for (auto [e] : cell->reg.view<SelectTag>().each()) {
    cell->reg.remove<SelectTag>(e);
  }
  m_select_render = true;
};

std::unordered_map<entt::entity, bool> SelectCmd::get_select_orders() {
  return m_select_orders;
};

void SelectCmd::add_select_order(const entt::entity& e) {
  m_select_orders[e] = true;
};

void SelectCmd::clear_select_order() {
  m_select_orders.clear();
};

void SelectCmd::clear_hover() {
  // 清除预选标记
  for (auto [e] : cell->reg.view<HoverTag>().each()) {
    cell->reg.remove<HoverTag>(e);
  }
  m_hover_render = true;
};

bool SelectCmd::hover_is_select() {
  auto select_view = cell->reg.view<SelectTag>();
  for (auto [e] : cell->reg.view<HoverTag>().each()) {
    if (select_view.contains(e))
      return true;
  }
  return false;
}

void SelectCmd::remove_tag(qlib::Tag& tag) {
  for (auto [e, s_tag] : cell->reg.view<SelectTag, qlib::Tag>().each()) {
    if (s_tag == tag) {
      cell->reg.remove<SelectTag>(e);
    }
  }

  for (auto [e, s_tag] : cell->reg.view<HoverTag, qlib::Tag>().each()) {
    if (s_tag == tag) {
      cell->reg.remove<HoverTag>(e);
    }
  }

  EntityArray del_parts;
  for (auto& [e, part] : m_select_parts) {
    auto s_tag = cell->reg.try_get<qlib::Tag>(e);
    if (tag == *s_tag) {
      del_parts.push_back(e);
    }
  }
  remove_select_parts(del_parts);

  del_parts.clear();
  for (auto& [e, part] : m_hover_parts) {
    auto s_tag = cell->reg.try_get<qlib::Tag>(e);
    if (tag == *s_tag) {
      del_parts.push_back(e);
    }
  }
  remove_hover_parts(del_parts);

  m_select_render = true;
  m_hover_render = true;
  m_select_part_render = true;
  m_hover_part_render = true;
}

// 取反选择
void SelectCmd::reverse_selects(const EntityArray& e_arr) {
  auto select_view = cell->reg.view<SelectTag>();
  for (auto& e : e_arr) {
    auto tag = cell->reg.try_get<qlib::Tag>(e);
    if (tag) {
      // 过滤隐藏图层
      if (!layer_manager.is_hide(*tag)) {
        if (select_view.contains(e)) {
          cell->reg.remove<SelectTag>(e);
        } else {
          cell->reg.emplace_or_replace<SelectTag>(e, SelectTag{});
        }
      }
    }
    auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(e);
    if (ref) {
      if (select_view.contains(e)) {
        cell->reg.remove<SelectTag>(e);
      } else {
        cell->reg.emplace_or_replace<SelectTag>(e, SelectTag{});
      }
    }
  }
  m_select_render = true;
};

void SelectCmd::add_part(SelectPartData& src_part, SelectPartData& part, bool is_path, bool is_fan) {
  auto n = src_part.points.size();
  auto& edge = part.edge_id_map;
  auto& point = part.point_id_map;
  auto& src_edge = src_part.edge_id_map;
  auto& src_point = src_part.point_id_map;

  bool is_add_arc_edge = false;
  bool is_add_arc = false;
  // 添加点
  for (auto& [id, ok] : point) {
    src_point[id] = true;
  }
  // 添加边及边上两点
  for (auto& [id, ok] : edge) {
    src_edge[id] = true;
    src_point[id] = true;
    src_point[(id + 1) % n] = true;
  }

  // 扫描连续点，补全边
  uint32_t pre_id = 10e9;
  for (auto& [id, ok] : src_point) {
    // 存在连续点, 设置边被选中
    if (pre_id + 1 == id) {
      src_edge[pre_id] = true;
    }
    pre_id = id;

    if (is_fan) {
      if (id > 1 && id < n - 1) {
        is_add_arc_edge = true;
      }
    }
  }
  // 最后一个点和第一个点特殊处理
  if (!is_path) {
    if (src_point.find(0) != src_point.end() && src_point.find(n - 1) != src_point.end()) {
      src_edge[n - 1] = true;
    }
  }

  // 扇形
  if (is_fan) {
    for (auto& [id, ok] : src_point) {
      if (id > 1 && id < n - 1) {
        is_add_arc_edge = true;
      }
    }
    for (auto& [id, ok] : src_edge) {
      if (id > 1 && id < n - 1) {
        is_add_arc_edge = true;
      }
    }
    if (src_point.find(1) != src_point.end() && src_point.find(n - 1) != src_point.end()) {
      is_add_arc_edge = true;
    }

    if (is_add_arc_edge) {
      // 删除弧上的点
      for (auto i = 2; i < n - 1; i++) {
        src_point.erase(i);
      }
      // 选择所有弧形边
      for (auto i = 1; i < n - 1; i++) {
        src_edge[i] = true;
      }
      // 弧上两个点
      src_point[1] = true;
      src_point[n - 1] = true;
    }
  }
};

void SelectCmd::add_parts(PartMap& src_parts, PartMap& parts, bool is_change) {
  if (is_change) {
    for (auto& [e, part] : parts) {
      // 过滤隐藏图层
      auto tag = cell->reg.try_get<qlib::Tag>(e);
      if (tag) {
        if (layer_manager.is_hide(*tag)) {
          continue;
        }
      }

      auto path = cell->reg.try_get<qlib::Path::s_ptr>(e);
      auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);

      auto& src_part = src_parts[e];
      src_part.points = part.points;
      add_part(src_part, part, bool(path), bool(fan));
    }
  } else {
    for (auto& [e, part] : parts) {
      auto& dst_part = src_parts[e];
      dst_part.points = part.points;
      for (auto& [id, ok] : part.edge_id_map) {
        dst_part.edge_id_map[id] = ok;
      }
      for (auto& [id, ok] : part.point_id_map) {
        dst_part.point_id_map[id] = ok;
      }
    }
  }
};

void SelectCmd::remove_part(SelectPartData& src_part, SelectPartData& part, bool is_path, bool is_fan) {
  auto n = src_part.points.size();
  auto& edge = part.edge_id_map;
  auto& point = part.point_id_map;
  auto& src_edge = src_part.edge_id_map;
  auto& src_point = src_part.point_id_map;
  bool is_remove_arc_edge = false;
  bool is_remove_arc = false;
  for (auto& [id, ok] : edge) {
    // 删除边
    src_edge.erase(id);
    // 删除边附近的两个点
    src_point.erase(id);
    src_point.erase((id + 1) % n);

    // 检查被删除的两个点是否存在边, 存在需要删除边
    int32_t pre_id = id - 1;
    int32_t next_id = id + 1;
    if (pre_id < 0) {
      pre_id = n - 1;
      if (is_path) {
        pre_id = id;
      }
    }
    if (next_id == n) {
      next_id = 0;
      if (is_path) {
        next_id = id;
      }
    }

    if (is_fan) {
      // 删除的边在扇形弧上，删除弧边
      if (id > 0 && id < n - 1) {
        is_remove_arc_edge = true;
      }
      // 删除的边为扇形的两侧，删除弧线
      if (id == 0 || id == n - 1) {
        is_remove_arc = true;
      }
    }

    src_edge.erase(pre_id);
    src_edge.erase(next_id);
  }

  // 删除点
  for (auto& [id, ok] : point) {
    src_point.erase(id);
    // 删除点附近的两条边
    int32_t pre_id = id - 1;
    int32_t next_id = id;
    if (pre_id < 0) {
      pre_id = n - 1;
      if (is_path) {
        pre_id = id;
      }
    }
    if (next_id == n) {
      next_id = 0;
      if (is_path) {
        next_id = id;
      }
    }

    if (is_fan) {
      if (id > 1 && id < n - 1) {
        is_remove_arc_edge = true;
      }
      if (id == 1 || id == n - 1) {
        is_remove_arc = true;
      }
    }

    src_edge.erase(pre_id);
    src_edge.erase(next_id);
  }

  if (is_fan) {
    if (is_remove_arc_edge) {
      // 删除所有弧形边
      for (auto i = 1; i < n - 1; i++) {
        src_edge.erase(i);
      }
      src_edge.erase(0);
      src_edge.erase(n - 1);
      src_point.erase(1);
      src_point.erase(n - 1);
    }
    if (is_remove_arc) {
      // 删除所有弧形边
      for (auto i = 1; i < n - 1; i++) {
        src_edge.erase(i);
      }
    }
  }

  m_select_part_render = true;
};

void SelectCmd::remove_parts(PartMap& src_parts, PartMap& parts, bool is_change) {
  if (is_change) {
    for (auto& [e, part] : parts) {
      // 过滤隐藏图层
      auto tag = cell->reg.try_get<qlib::Tag>(e);
      if (tag) {
        if (layer_manager.is_hide(*tag)) {
          continue;
        }
      }
      auto path = cell->reg.try_get<qlib::Path::s_ptr>(e);
      auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);
      auto& src_part = src_parts[e];
      src_part.points = part.points;
      remove_part(src_part, part, bool(path), bool(fan));
    }
  } else {
    for (auto& [e, part] : parts) {
      if (src_parts.find(e) == src_parts.end())
        continue;
      auto& dst_part = src_parts[e];
      dst_part.points = part.points;
      std::vector<uint32_t> remove_edges;
      for (auto& [id, ok] : part.edge_id_map) {
        remove_edges.push_back(id);
      }
      std::vector<uint32_t> remove_points;
      for (auto& [id, ok] : part.point_id_map) {
        remove_points.push_back(id);
      }
      for (auto& id : remove_edges) {
        dst_part.edge_id_map.erase(id);
      }
      for (auto& id : remove_points) {
        dst_part.point_id_map.erase(id);
      }
    }
  }
  m_select_part_render = true;
};

void SelectCmd::clear_parts() {
  m_hover_parts.clear();
  m_select_parts.clear();
  m_select_part_render = true;
  m_hover_part_render = true;
};

void SelectCmd::filter_select_parts(PartMap& parts, EntityArray& res_selects) {
  // 检测对象的选中的部分是否包含对象部分的所有点，包含，标记对象为全选
  for (auto& [e, part] : parts) {
    if (is_overall_part(e, part)) {
      res_selects.push_back(e);
    }
  }
}

// bool SelectCmd::check_select_part_overall(const entt::entity& e) {
//   auto& part = m_select_parts[e];
//   return select_cmd.is_overall_part(e, part);
// }

void SelectCmd::overall_part(entt::entity e, SelectPartData& part) {
  auto n = part.points.size();
  auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);
  for (uint32_t i = 0; i < n; i++) {
    if (fan) {
      if (i < 2 || i > n - 2) {
        part.point_id_map[i] = true;
      }
    } else {
      part.point_id_map[i] = true;
    }
    part.edge_id_map[i] = true;
  }
}

void SelectCmd::overall_parts(PartMap& parts) {
  for (auto& [e, part] : parts) {
    overall_part(e, part);
  }
}

bool SelectCmd::is_overall_part(entt::entity e, SelectPartData& part) {
  auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);
  auto& points = part.points;
  auto& point_id_map = part.point_id_map;
  auto n = points.size();
  std::map<uint32_t, bool> all_points_map;
  for (uint32_t i = 0; i < n; i++)
    all_points_map[i] = true;

  for (auto& [id, ok] : all_points_map) {
    if (fan) {
      if (id == 0 || id == 1 || id == n - 1) {
        if (point_id_map.find(id) == point_id_map.end()) {
          return false;
        }
      }
    } else {
      if (point_id_map.find(id) == point_id_map.end()) {
        return false;
      }
    }
  }
  return true;
}

void SelectCmd::query_nodes(double x, double y) {
  auto r = range;
  quadtree::Box<double> q_box = quadtree::Box(x - r, y - r, 2 * r, 2 * r);
  m_nodes = cell->quad->query(q_box);
}

void SelectCmd::query_nodes(double x, double y, double w, double h) {
  // 四叉树查询鼠标周围对象
  quadtree::Box<double> q_box = quadtree::Box(x, y, w, h);
  m_nodes = cell->quad->query(q_box);
}

bool SelectCmd::get_adsorb(double x, double y, qlib::Vec2d& point, qlib::GeoPartType& type) {
  select::SelectCmd::PartNodes nodes;
  auto is_find = get_part_type(x, y, nodes);
  if (is_find) {
    auto& node = nodes[0];
    type = node.type;
    if (node.edge.size() > 0) {
      // 边, 计算点到边的投影点
      auto ok = projectPointToSegment(node.edge[0], node.edge[1], qlib::Vec2d{x, y}, point);
      if (ok) {
        return true;
      }
    } else {
      // 点
      point = node.point;
      return true;
    }
  }
  return false;
}

bool SelectCmd::get_part_type(double x, double y, PartNodes& res) {
  query_nodes(x, y);
  auto r = range;
  // 鼠标位置
  auto mouse_point = qlib::Vec2d{x, y};
  struct NPart {
    // uint8_t type{0};  // 1: 点， 2: 边
    // qlib::Vec2dArray points;
    // qlib::Vec2d point;
    // qlib::Vec2dArray edge;  // 边：size = 2, 点：size = 1
    // bool exist{false};
    // double max_d{1e10};
    // uint32_t id;
    entt::entity e;
    layout::SelectQuad::Node node;
  };

  std::unordered_map<qlib::GeoPartType, std::map<double, NPart>> edges;
  std::unordered_map<qlib::GeoPartType, std::map<double, NPart>> points;

  auto f_cacl_distance = cacl_distance;
  auto find_part = [&](auto& parts, auto& mouse_pos, auto e) {
    for (auto part : parts) {
      // 边
      if (part.edge.size() > 0) {
        auto d = f_cacl_distance(mouse_pos, part.edge);
        if (d < r) {
          edges[part.type][d] = NPart{e, part};
        }
      } else {
        auto d = mouse_pos.distance(part.point);
        if (part.type == qlib::GeoPartType::Center) {
          d = 0.001;
        }
        if (d < r) {
          points[part.type][d] = NPart{e, part};
        }
      }
    }
  };
  auto find_part_ref = [&](auto& parts, auto& mouse_pos, auto e, auto ref, auto offset) {
    for (auto part : parts) {
      // 边
      if (part.edge.size() > 0) {
        auto d = f_cacl_distance(mouse_pos, part.edge);
        if (d < r) {
          part.edge[0] = tran_to_cell_point(part.edge[0], ref) + offset;
          part.edge[1] = tran_to_cell_point(part.edge[1], ref) + offset;
          edges[part.type][d] = NPart{e, part};
        }
      } else {
        auto d = mouse_pos.distance(part.point);
        if (part.type == qlib::GeoPartType::Center) {
          d = 0.001;
        }
        if (d < r) {
          part.point = tran_to_cell_point(part.point, ref) + offset;
          points[part.type][d] = NPart{e, part};
        }
      }
    }
  };

  auto is_hide = [&](auto& reg, auto& e) {
    // 过滤隐藏图层
    auto tag = reg.try_get<qlib::Tag>(e);
    if (tag) {
      if (layer_manager.is_hide(*tag)) {
        return true;
      }
    }
    return false;
  };
  // 查询节点
  for (auto& node : m_nodes) {
    // ref
    auto ref_ptr = cell->reg.try_get<qlib::Reference::s_ptr>(node.entity);
    if (ref_ptr) {
      auto ref = *ref_ptr;
      // // 检测鼠标位置是否在引用包围盒子内部
      // if (!is_point_in_rect(mouse_point, ref->box)) {
      //   continue;
      // }
      auto& ref_reg = ref->cell->ref_cache_reg;
      auto& ref_quad = ref->cell->ref_cache_quad;

      if (ref->repetition.type == qlib::RepetitionType::None) {
        // 查询ref内部cell鼠标周围对象
        auto ref_p = tran_to_ref_point(mouse_point, ref);
        SPDLOG_INFO("ref-p >> x:{}, y:{}", ref_p.x, ref_p.y);
        auto ref_nodes = ref_quad->query(quadtree::Box<double>(ref_p.x - r, ref_p.y - r, 2 * r, 2 * r));
        for (auto& ref_node : ref_nodes) {
          if (is_hide(ref_reg, ref_node.entity))
            continue;
          // 查询引用内部几何的部分
          std::vector<layout::SelectQuad::Node> ref_part_nodes;
          query_geo_part_multi(ref->cell->ref_cache_reg, ref_node.entity, ref_p.x - r, ref_p.y - r, 2 * r, 2 * r, ref_part_nodes, GeoTypes());
          find_part_ref(ref_part_nodes, ref_p, node.entity, ref, qlib::Vec2d{0, 0});
        }
      }

      if (ref->repetition.type != qlib::RepetitionType::None) {
        auto ref_rep = ref->copy();
        ref_rep->repetition = qlib::RepetitionType::None;
        auto ref_p = tran_to_ref_point(mouse_point, ref_rep);

        // 通过cell的包围盒子来确定kdtree查询范围
        auto ref_cell_box = ref->cell->bounding_box();
        auto w = ref_cell_box[1].x - ref_cell_box[0].x;
        auto h = ref_cell_box[1].y - ref_cell_box[0].y;
        auto rad = w > h ? 2.5 * w : 2.5 * h;

        // 展开阵列偏移点位
        qlib::Vec2dArray offsets;
        ref->repetition.get_offsets(offsets);
        pointVec point_vec;
        for (auto& p : offsets) {
          point_vec.push_back(point_t{p.x, p.y});
        }
        // 创建KDTree，查找最近阵列对象
        KDTree kdtree(point_vec);
        SPDLOG_INFO("ref-repetition >> [cell_box w:{}, h:{}] ,rad: {}", w, h, rad);
        qlib::Vec2d find_p{mouse_point.x - ref->origin.x, mouse_point.y - ref->origin.y};
        SPDLOG_INFO("ref-repetition >> [find_p [{:.3f}, {:.3f}]", find_p.x, find_p.y);
        auto neigh_ps = kdtree.neighborhood_points(point_t{find_p.x, find_p.y}, rad);
        // auto neigh_ps = kdtree.neighborhood_points(point_t{ref_p.x, ref_p.y}, rad);
        for (auto& np : neigh_ps) {
          SPDLOG_INFO("np >> x:{}, y:{}", np[0], np[1]);
          if (np.size() > 0) {
            // 转换鼠标点位到阵列内部
            auto offset_p = qlib::Vec2d{np[0], np[1]};
            auto offset_mouse_p = qlib::Vec2d{ref_p.x - np[0], ref_p.y - np[1]};
            auto ref_nodes = ref_quad->query(quadtree::Box<double>(offset_mouse_p.x - r, offset_mouse_p.y - r, 2 * r, 2 * r));
            for (auto& ref_node : ref_nodes) {
              if (is_hide(ref_reg, ref_node.entity))
                continue;
              // 查询引用内部几何的部分
              std::vector<layout::SelectQuad::Node> part_nodes;
              query_geo_part_multi(ref->cell->ref_cache_reg, ref_node.entity, offset_mouse_p.x - r, offset_mouse_p.y - r, 2 * r, 2 * r, part_nodes,
                                   GeoTypes());
              find_part_ref(part_nodes, offset_mouse_p, node.entity, ref, offset_p);
            }
          }
        }
      }
      continue;
    }
    // 过滤隐藏图层
    if (is_hide(cell->reg, node.entity))
      continue;
    // geo
    std::vector<layout::SelectQuad::Node> part_nodes;
    query_geo_part_multi(cell->reg, node.entity, x - r, y - r, 2 * r, 2 * r, part_nodes, GeoTypes());
    find_part(part_nodes, mouse_point, node.entity);
  }

  // 点的优先级高于边
  NPart ok_part;
  if (points.size() > 0) {
    for (auto& [type, d_edges] : points) {
      if (type == qlib::GeoPartType::Center) {
        ok_part = d_edges.begin()->second;
        break;
      } else if (type == qlib::GeoPartType::BoxEdgeMid) {
        ok_part = d_edges.begin()->second;
        break;
      } else if (type == qlib::GeoPartType::EdgeMid) {
        ok_part = d_edges.begin()->second;
        break;
      } else {
        ok_part = d_edges.begin()->second;
      }
    }
  } else {
    for (auto& [type, d_points] : edges) {
      ok_part = d_points.begin()->second;
      // ok_part = *(d_points.begin());
      break;
    }
  }
  // NPart n = point.exist ? point : edge;

  if (points.size() > 0 || edges.size() > 0) {
    res.push_back(ok_part.node);
    // auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(ok_part.e);
    // if (ref) {
    //   for (auto& p : res) {
    //     if (p.edge.size() > 0) {
    //       p.edge[0] = tran_to_cell_point(p.edge[0], *ref);
    //       p.edge[1] = tran_to_cell_point(p.edge[1], *ref);
    //     } else {
    //       p.point = tran_to_cell_point(p.point, *ref);
    //     }
    //   }
    // }
    return true;
  }

  return false;
}

bool SelectCmd::get_part(double x, double y, PartMap& res, bool is_ref, bool is_point, bool is_edge) {
  query_nodes(x, y);
  auto nodes = m_nodes;
  auto r = range;

  // 鼠标位置
  auto mouse_point = qlib::Vec2d{x, y};

  struct NearestPart {
    uint8_t type{0};  // 1: 点， 2: 边
    qlib::Vec2dArray points;
    qlib::Vec2d point;
    qlib::Vec2dArray edge;  // 边：size = 2, 点：size = 1
    bool exist{false};
    double max_d{1e10};
    uint32_t id;

    entt::entity e;
    layout::SelectQuad::Node node;
  };

  NearestPart point{1};
  NearestPart edge{2};

  GeoTypes geo_types;
  auto f_cacl_distance = cacl_distance;
  auto find_part = [&](auto& part, auto& mouse_pos, auto e) {
    auto& ps = part.points;
    auto n = part.points.size();
    if (ps.size() == 0)
      return;
    if (is_edge) {
      for (auto& [id, ok] : part.edge_id_map) {
        auto d = f_cacl_distance(mouse_pos, part.get_edge(id));
        // 检测最近
        if (d < r && d < edge.max_d) {
          edge.points = ps;
          edge.id = id;
          edge.exist = true;
          edge.max_d = d;
          edge.e = e;
        }
      }
    }
    if (is_point) {
      for (auto& [id, ok] : part.point_id_map) {
        auto d = mouse_pos.distance(part.get_point(id));
        // 检测最近
        if (d < r && d < point.max_d) {
          point.points = ps;
          point.id = id;
          point.exist = true;
          point.max_d = d;
          point.e = e;
        }
      }
    }
  };

  auto is_hide = [&](auto& reg, auto& e) {
    // 过滤隐藏图层
    auto tag = reg.try_get<qlib::Tag>(e);
    if (tag) {
      if (layer_manager.is_hide(*tag)) {
        return true;
      }
    }
    return false;
  };

  // 依次查询各个对象最近的部分
  for (auto& node : nodes) {
    if (is_ref) {
      // ref
      auto ref_ptr = cell->reg.try_get<qlib::Reference::s_ptr>(node.entity);
      if (ref_ptr) {
        auto ref = *ref_ptr;
        auto& ref_reg = ref->cell->ref_cache_reg;
        auto& ref_quad = ref->cell->ref_cache_quad;
        // 查询ref内部cell鼠标周围对象
        auto ref_p = tran_to_ref_point(mouse_point, ref);
        auto ref_nodes = ref_quad->query(quadtree::Box<double>(ref_p.x - r, ref_p.y - r, 2 * r, 2 * r));
        for (auto& ref_node : ref_nodes) {
          if (is_hide(ref_reg, ref_node.entity))
            continue;
          // 查询引用内部几何的部分
          SelectPartData ref_part = {};
          query_part_multi(ref_reg, ref_node.entity, ref_p.x - r, ref_p.y - r, 2 * r, 2 * r, ref_part, geo_types);
          find_part(ref_part, ref_p, node.entity);
        }
        SPDLOG_INFO("mouse({}, {}) in ref~", mouse_point.x, mouse_point.y);
        SPDLOG_INFO("ref_p: ({}, {}) ~", ref_p.x, ref_p.y);
        continue;
      }
    }

    if (is_hide(cell->reg, node.entity))
      continue;
    SelectPartData geo_part = {};
    query_part_multi(cell->reg, node.entity, x - r, y - r, 2 * r, 2 * r, geo_part, geo_types);
    find_part(geo_part, mouse_point, node.entity);
  }

  // 点的优先级高于边
  NearestPart n = point.exist ? point : edge;
  auto& part = res[n.e];

  if (n.exist) {
    part.points = n.points;
    if (n.type == 1) {
      part.point_id_map[n.id] = true;
    } else {
      part.edge_id_map[n.id] = true;
    }
  }

  auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(n.e);
  if (ref) {
    for (auto& p : part.points) {
      p = tran_to_cell_point(p, *ref);
    }
  }

  return n.exist;
}

bool SelectCmd::query_box_part(std::vector<qlib::CellQuad::Node>& geo_nodes, const DrawBoxDirect& direct, double x, double y, double w, double h,
                               std::vector<std::pair<entt::entity, layout::SelectQuad::Node>>& res) {
  // auto& reg = cell->reg;
  // for (auto& geo_node : geo_nodes) {
  //   auto ref = reg.try_get<qlib::Reference::s_ptr>(geo_node.entity);
  //   if (ref) {
  //     continue;
  //   }

  //   // 依次查询几何对象
  //   std::vector<layout::SelectQuad::Node> part_nodes = {};
  //   GeoTypes geo_types;
  //   query_part_multi(reg, geo_node.entity, x, y, w, h, part_nodes, geo_types);
  //   for (auto& n : part_nodes) {
  //     // 右框选时需要完全包含对象
  //     if (direct == select::DrawBoxDirect::Right) {
  //       select::Rect rect_outer = {x, y, w, h};
  //       select::Rect rect_inner = {n.box.left, n.box.top, n.box.width, n.box.height};
  //       // 检查全包含
  //       if (is_rect_contained(rect_outer, rect_inner)) {
  //         res.push_back(std::make_pair(geo_node.entity, n));
  //       }
  //     }
  //     // 左框 相交，四叉树扫描到的对象一定相交
  //     if (direct == select::DrawBoxDirect::Left) {
  //       res.push_back(std::make_pair(geo_node.entity, n));
  //     }
  //   }
  // }

  return false;
}

// 是否相交
bool SelectCmd::is_intersect(entt::registry& reg, const entt::entity& e, const Rect& box) {

  auto gf = geos::geom::GeometryFactory::create();
  auto get_geos_line = [&gf](const qlib::Vec2dArray& points) {
    auto g_ls = gf->createLineString(std::move(get_coordseq(points)));
    return std::move(g_ls);
  };
  auto get_geos_poly = [&gf](const qlib::Vec2dArray& points) {
    auto g_pl = gf->createPolygon(std::move(get_coordseq(points)));
    return std::move(g_pl);
  };

  auto box_points = qlib::Vec2dArray{
      {box.x, box.y}, {box.x + box.width, box.y}, {box.x + box.width, box.y + box.height}, {box.x, box.y + box.height}, {box.x, box.y}};

  // auto box_poly = geos_fy->createPolygon(std::move(get_coordseq(box_points)));
  auto box_poly = get_geos_poly(box_points);

  bool is_inter = false;

  auto path = reg.try_get<qlib::Path::s_ptr>(e);
  if (path) {
    if ((*path)->width > 0) {
      qlib::PolygonPtrArray polys;
      (*path)->to_polygons(false, qlib::Tag{0, 0}, polys);
      for (auto poly : polys) {
        auto points = qlib::connect_end(poly->points);
        is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
        if (is_inter)
          break;
      }
    } else {
      is_inter = box_poly.get()->intersects(get_geos_line((*path)->spine.points).get());
    }
    // SPDLOG_INFO("path box inter: {} ", is_inter);
    return is_inter;
  }

  auto poly = reg.try_get<qlib::Polygon::s_ptr>(e);
  if (poly) {
    auto points = qlib::connect_end((*poly)->points);
    is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
    return is_inter;
  }

  auto rect = reg.try_get<qlib::Rectangle::s_ptr>(e);
  if (rect) {
    auto points = qlib::connect_end((*rect)->to_polygon()->points);
    is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
    return is_inter;
  }

  auto ellipse = reg.try_get<qlib::Ellipse::s_ptr>(e);
  if (ellipse) {
    auto points = qlib::connect_end((*ellipse)->to_polygon()->points);
    is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
    return is_inter;
  }

  auto circle = reg.try_get<qlib::Circle::s_ptr>(e);
  if (circle) {
    auto points = qlib::connect_end((*circle)->to_polygon()->points);
    is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
    return is_inter;
  }

  auto fan = reg.try_get<qlib::Fan::s_ptr>(e);
  if (fan) {
    auto points = qlib::connect_end((*fan)->to_polygon()->points);
    is_inter = box_poly.get()->intersects(get_geos_poly(points).get());
    return is_inter;
  }

  auto label = reg.try_get<qlib::Label::s_ptr>(e);
  if (label) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::box_to_points((*label)->box)).get());
    return is_inter;
  }

  auto kpoint = reg.try_get<qlib::KeyPoint::s_ptr>(e);
  if (kpoint) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::box_to_points((*kpoint)->box)).get());
    return is_inter;
  }

  auto pin = reg.try_get<qlib::Pin::s_ptr>(e);
  if (pin) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::box_to_points((*pin)->box)).get());
    return is_inter;
  }

  auto text = reg.try_get<qlib::Text::s_ptr>(e);
  if (text) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::box_to_points((*text)->box)).get());
    return is_inter;
  }

  auto ruler = reg.try_get<qlib::Ruler::s_ptr>(e);
  if (ruler) {
    auto points = qlib::Vec2dArray{(*ruler)->start, (*ruler)->end};
    is_inter = box_poly.get()->intersects(get_geos_line(points).get());
    return is_inter;
  }

  auto fly_line = reg.try_get<qlib::FlyLine::s_ptr>(e);
  if (fly_line) {
    auto points = (*fly_line)->get_points();
    is_inter = box_poly.get()->intersects(get_geos_line(points).get());
    return is_inter;
  }

  auto view3d = reg.try_get<qlib::ViewArea3D::s_ptr>(e);
  if (view3d) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::connect_end((*view3d)->points)).get());
    return is_inter;
  }

  auto section3d = reg.try_get<qlib::SectionArea3D::s_ptr>(e);
  if (section3d) {
    is_inter = box_poly.get()->intersects(get_geos_line((*section3d)->to_polygon()->points).get());
    return is_inter;
  }

  auto ref = reg.try_get<qlib::Reference::s_ptr>(e);
  if (ref) {
    is_inter = box_poly.get()->intersects(get_geos_poly(qlib::box_to_points((*ref)->box)).get());
    // is_inter = box_poly.get()->intersects(get_geos_line((*ref)->bounding_box_points()).get());
    return is_inter;
  }
  return is_inter;
}

// 最近选择
void SelectCmd::get_select(double x, double y, std::multimap<double, entt::entity>& res_border) {
  // 查询附近对象
  query_nodes(x, y);

  auto r = range;
  // 查询鼠标周围的节点
  auto& nodes = m_nodes;

  auto gf = geos::geom::GeometryFactory::create();
  auto mouse_point_qb = qlib::Vec2{x, y};
  auto mouse_point = gf->createPoint(geos::geom::Coordinate{x, y});
  auto mouse_circle = mouse_point->buffer(r);

  struct SelectNode {
    double d;      // 轮廓距离
    double end_d;  // 端点距离
    entt::entity e;
  };

  std::map<entt::entity, SelectNode> in_objs = {};
  std::map<entt::entity, SelectNode> out_objs = {};

  auto connect_end = [](const qlib::Vec2dArray& points) {
    auto res = points;
    res.push_back(points[0]);
    return res;
  };

  // 检测边框、区域相交
  auto scan_inter = [&](auto& e, auto& points, bool check_border = true, bool check_area = true) {
    std::vector<geos::geom::Coordinate> coords;
    for (auto& p : points) {
      coords.push_back(geos::geom::Coordinate{p.x, p.y});
    }
    geos::geom::CoordinateSequence coord_seq;
    coord_seq.setPoints(coords);
    auto g_line = gf->createLineString(std::move(coord_seq));
    auto d = mouse_point->distance(g_line.get());
    double end_d = -1.0;
    auto path = cell->reg.try_get<qlib::Path::s_ptr>(e);
    if (path) {
      auto d1 = mouse_point_qb.distance(points[0]);
      auto d2 = mouse_point_qb.distance(points[points.size() - 1]);
      end_d = d1 < d2 ? d1 : d2;
    }
    auto ruler = cell->reg.try_get<qlib::Ruler::s_ptr>(e);
    if (ruler) {
      auto d1 = mouse_point_qb.distance(points[0]);
      auto d2 = mouse_point_qb.distance(points[points.size() - 1]);
      end_d = d1 < d2 ? d1 : d2;
    }
    // end_d = end_d < r ? end_d : -1.0;

    if (check_border) {
      // 边框相交
      if (d < r) {
        res_border.insert({d, e});
        // 筛选距离最近
        if (out_objs.find(e) != out_objs.end()) {
          if (d < out_objs[e].d) {
            out_objs.insert({e, {d, end_d, e}});
          }
        } else {
          out_objs.insert({e, {d, end_d, e}});
        }
      }
    }
    if (check_area) {
      // 区域相交
      auto g_poly = gf->createPolygon(std::move(coord_seq));
      if (mouse_circle->intersects(g_poly.get())) {
        res_border.insert({d, e});
        // 剔除相同对象到轮廓的对象，只保留内部的，内部的优先级低
        if (out_objs.find(e) != out_objs.end()) {
          out_objs.erase(e);
        }
        // 筛选距离最近
        if (in_objs.find(e) != in_objs.end()) {
          if (d < in_objs[e].d) {
            in_objs.insert({e, {d, end_d, e}});
          }
        } else {
          in_objs.insert({e, {d, end_d, e}});
        }
      }
    }
  };

  for (auto& n : nodes) {
    auto& e = n.entity;
    auto path = cell->reg.try_get<qlib::Path::s_ptr>(e);
    if (path) {
      if ((*path)->width > 0) {
        qlib::PolygonPtrArray polys;
        (*path)->to_polygons(false, qlib::Tag{0, 0}, polys);
        for (auto poly : polys) {
          auto points = qlib::connect_end(poly->points);
          scan_inter(e, points);
        }
      } else {
        // path
        scan_inter(e, (*path)->spine.points, true, false);
      }
      continue;
    }
    auto poly = cell->reg.try_get<qlib::Polygon::s_ptr>(e);
    if (poly) {
      scan_inter(e, connect_end((*poly)->points));
      continue;
    }
    auto rect = cell->reg.try_get<qlib::Rectangle::s_ptr>(e);
    if (rect) {
      scan_inter(e, connect_end((*rect)->to_polygon()->points));
      continue;
    }
    auto circle = cell->reg.try_get<qlib::Circle::s_ptr>(e);
    if (circle) {
      scan_inter(e, connect_end((*circle)->to_polygon()->points));
      continue;
    }
    auto ellipse = cell->reg.try_get<qlib::Ellipse::s_ptr>(e);
    if (ellipse) {
      scan_inter(e, connect_end((*ellipse)->to_polygon()->points));
      continue;
    }
    auto fan = cell->reg.try_get<qlib::Fan::s_ptr>(e);
    if (fan) {
      scan_inter(e, connect_end((*fan)->to_polygon()->points));
      continue;
    }
    auto label = cell->reg.try_get<qlib::Label::s_ptr>(e);
    if (label) {
      scan_inter(e, qlib::box_to_points((*label)->box));
      continue;
    }
    auto pin = cell->reg.try_get<qlib::Pin::s_ptr>(e);
    if (pin) {
      scan_inter(e, qlib::box_to_points((*pin)->box));
      continue;
    }
    auto kpoint = cell->reg.try_get<qlib::KeyPoint::s_ptr>(e);
    if (kpoint) {
      scan_inter(e, qlib::box_to_points((*kpoint)->box));
      continue;
    }
    auto text = cell->reg.try_get<qlib::Text::s_ptr>(e);
    if (text) {
      scan_inter(e, qlib::box_to_points((*text)->box));
      continue;
    }
    auto ruler = cell->reg.try_get<qlib::Ruler::s_ptr>(e);
    if (ruler) {
      auto points = qlib::Vec2dArray{(*ruler)->start, (*ruler)->end};
      scan_inter(e, points, true, false);
      continue;
    }
    auto fly_line = cell->reg.try_get<qlib::FlyLine::s_ptr>(e);
    if (fly_line) {
      auto points = (*fly_line)->get_points();
      scan_inter(e, points, true, false);
      continue;
    }
    auto view3d = cell->reg.try_get<qlib::ViewArea3D::s_ptr>(e);
    if (view3d) {
      scan_inter(e, connect_end((*view3d)->points));
      continue;
    }
    auto section3d = cell->reg.try_get<qlib::SectionArea3D::s_ptr>(e);
    if (section3d) {
      scan_inter(e, connect_end((*section3d)->to_polygon()->points));
      continue;
    }

    auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(e);
    if (ref) {
      scan_inter(e, qlib::box_to_points((*ref)->box));
      continue;
    }
  }

  // 排序 + 轮廓筛选
  res_border.clear();
  // std::multimap<double, entt::entity> end_objs;
  std::multimap<double, SelectNode> end_objs;

  SPDLOG_INFO("find>>>>>>>>>>>>");
  for (auto& [e, n] : out_objs) {
    SPDLOG_INFO("out_objs >>>  e: {}, d: {}, end_d: {}", uint32_t(e), n.d, n.end_d);
    if (n.end_d >= 0 && n.end_d < r) {
      end_objs.insert({n.end_d, n});
    }
  }

  for (auto& [d, n] : end_objs) {
    out_objs.erase(n.e);
    res_border.insert({n.end_d, n.e});
  }

  for (auto& [e, n] : out_objs) {
    res_border.insert({n.d, e});
    // if (n.end_d > 0) {
    //   end_objs.insert({n.end_d, e});
    // }
  }
  for (auto& [e, n] : in_objs) {
    res_border.insert({n.d, e});
  }

  // // 去重
  // std::map<entt::entity, std::vector<double>> e_map;
  // for (auto& [d, e] : res_border) {
  //   e_map[e].push_back(d);
  // }
  // res_border.clear();
  // for (auto& [e, d_arr] : e_map) {
  //   // 获取最小值的迭代器
  //   auto min_it = std::min_element(d_arr.begin(), d_arr.end());
  //   res_border.insert({double(*min_it), e});
  //   // res_border[double(*min_it)] = e;
  // }
}

void SelectCmd::get_box_part(double x, double y, double w, double h, EntityArray& res_selects, PartMap& res_parts, DrawBoxDirect direct,
                             bool is_overall) {
  // 查询附近对象
  query_nodes(x, y, w, h);
  // 矩形-查询区域
  select::Rect rect_draw = {x, y, w, h};
  // auto rect_points = rect->bounding_box_points();
  auto rect_points = qlib::Vec2dArray{{x, y}, {x + w, y}, {x + w, y + h}, {x, y + h}, {x, y}};
  auto rect_box = qlib::Vec2dArray{{x, y}, {x + w, y + h}};

  GeoTypes geo_types;

  auto& geo_nodes = m_nodes;
  for (auto& geo_node : geo_nodes) {
    if (is_overall) {
      // 矩形-几何对象
      select::Rect rect_geo = {geo_node.box.left, geo_node.box.top, geo_node.box.width, geo_node.box.height};
      // 只要全包含，必然被选中, 跳过后续部分选择逻辑
      if (is_rect_contained(rect_draw, rect_geo)) {
        res_selects.push_back(geo_node.entity);
        continue;
      }
    }

    // ref 直接处理左框, 右框上面已经实现
    auto ref = cell->reg.try_get<qlib::Reference::s_ptr>(geo_node.entity);
    if (ref) {
      if (direct == select::DrawBoxDirect::Left) {
        if (is_intersect(cell->reg, geo_node.entity, rect_draw)) {
          res_selects.push_back(geo_node.entity);
        }
        continue;
      }
    }

    // 部分选择
    // SelectPartData part_nodes = {};
    // auto& part = res_parts[geo_node.entity];
    SelectPartData part;
    query_part_multi(cell->reg, geo_node.entity, x, y, w, h, part, geo_types);

    // 线段与矩形是否相交
    auto gf = geos::geom::GeometryFactory::create();
    auto& f_get_coordseq = get_coordseq;
    auto is_intersect_box = [&gf, &f_get_coordseq](const qlib::Vec2dArray geo1, const qlib::Vec2dArray& geo2) {
      auto g1 = gf->createLineString(f_get_coordseq(geo1));
      auto g2 = gf->createPolygon(f_get_coordseq(geo2));
      return g1.get()->intersects(g2.get());
    };
    SelectPartData ok_part;

    for (auto& [id, ok] : part.edge_id_map) {
      auto edge = part.get_edge(id);
      // 只要全包含，必然被选中, 满足右侧框选逻辑
      if (is_points_in_rect(edge, rect_box)) {
        ok_part.edge_id_map[id] = true;
        continue;
      }
      if (direct == select::DrawBoxDirect::Left) {
        if (is_intersect_box(edge, rect_points)) {
          ok_part.edge_id_map[id] = true;
        }
      }
    }

    for (auto& [id, ok] : part.point_id_map) {
      auto point = part.get_point(id);
      // 只要全包含，必然被选中, 满足右侧框选逻辑
      if (is_point_in_rect(point, rect_box)) {
        ok_part.point_id_map[id] = true;
      }
    }

    // for (auto& part_n : part_nodes) {
    //   select::Rect rect_part = {part_n.box.left, part_n.box.top, part_n.box.width, part_n.box.height};
    //   // 只要全包含，必然被选中, 满足右侧框选逻辑
    //   if (is_rect_contained(rect_draw, rect_part)) {
    //     ok_part_nodes.push_back(part_n);
    //     continue;
    //   }
    //   if (direct == select::DrawBoxDirect::Left) {
    //     if (part_n.edge.size() > 0) {  // 边
    //       if (is_intersect_box(part_n.edge, rect_points)) {
    //         ok_part_nodes.push_back(part_n);
    //       }
    //     } else {  // 点
    //       if (is_point_in_rect(part_n.point, rect_box)) {
    //         ok_part_nodes.push_back(part_n);
    //       }
    //     }
    //   }
    // }

    // 过滤边和点
    // auto& part = res_parts[geo_node.entity];
    // get_part_multi(cell->reg, geo_node.entity, part.points, geo_types);
    // for (auto& node : ok_part_nodes) {
    //   if (node.edge.size() > 0) {
    //     part.edge_id_map[node.id] = true;
    //   } else {
    //     part.point_id_map[node.id] = true;
    //   }
    // }

    if (ok_part.edge_id_map.size() > 0 || ok_part.point_id_map.size() > 0) {
      ok_part.points = part.points;
      PartMap ok_parts;
      ok_parts[geo_node.entity] = ok_part;
      add_parts(res_parts, ok_parts);
    }
  }
}

void SelectCmd::get_box_select(double x, double y, double w, double h, EntityArray& res, DrawBoxDirect direct) {
  // 查询附近对象
  query_nodes(x, y, w, h);
  // 矩形-查询区域
  select::Rect rect_draw = {x, y, w, h};

  auto geo_nodes = m_nodes;
  for (auto& geo_node : geo_nodes) {
    if (direct == DrawBoxDirect::Right) {}
    // 矩形-几何对象
    auto& box = geo_node.box;
    select::Rect rect_geo = {geo_node.box.left, geo_node.box.top, geo_node.box.width, geo_node.box.height};
    // 只要全包含，必然被选中, 跳过后续部分选择逻辑
    if (is_rect_contained(rect_draw, rect_geo)) {
      res.push_back(geo_node.entity);
      continue;
    }

    // 只处理左框选，右框选上面已经实现
    if (direct == select::DrawBoxDirect::Left) {
      // 存在相交，可以全选
      if (is_intersect(cell->reg, geo_node.entity, rect_draw)) {
        res.push_back(geo_node.entity);
      }
    }
  }
}

bool SelectCmd::hover_is_select_part() {
  auto& hover_parts = m_hover_parts;
  auto& select_parts = m_select_parts;
  auto select_view = cell->reg.view<SelectTag>();
  // 选择里面包含parts中的一部分
  for (auto& [e, h_part] : hover_parts) {
    if (select_view.contains(e))
      return true;
    // if(cell->reg.view<>())
    if (select_parts.find(e) != select_parts.end()) {
      auto& s_part = select_parts[e];
      // 边
      if (h_part.edge_id_map.size() > 0) {
        for (auto& [id, ok] : h_part.edge_id_map) {
          if (s_part.edge_id_map.find(id) != s_part.edge_id_map.end()) {
            return true;
          }
        }
      }
      // 点
      if (h_part.point_id_map.size() > 0) {
        for (auto& [id, ok] : h_part.point_id_map) {
          if (s_part.point_id_map.find(id) != s_part.point_id_map.end()) {
            return true;
          }
        }
      }
    }
  }
  return false;
}

// void SelectCmd::algin_add_hover_parts(PartMap& parts) {
//   add_parts(m_algin_hover_parts, parts, false);
//   m_algin_hover_part_render = true;
// }
void SelectCmd::algin_add_select_parts(PartMap& parts) {
  add_parts(m_algin_select_parts, parts, false);
  m_algin_select_part_render = true;
}

void SelectCmd::add_hover_parts(PartMap& parts, bool is_change) {
  auto& src_parts = m_hover_parts;
  add_parts(src_parts, parts, is_change);
  m_hover_part_render = true;
}

void SelectCmd::add_select_parts(PartMap& parts, bool is_change) {
  add_parts(m_select_parts, parts, is_change);
  m_select_part_render = true;
}

void SelectCmd::remove_hover_parts(PartMap& parts, bool is_change) {
  remove_parts(m_hover_parts, parts, is_change);
  m_hover_part_render = true;
}

void SelectCmd::remove_hover_parts(EntityArray& e_arr) {
  for (auto& e : e_arr) {
    m_hover_parts.erase(e);
  }
  m_hover_part_render = true;
}

void SelectCmd::remove_select_parts(PartMap& parts, bool is_change) {
  remove_parts(m_select_parts, parts, is_change);
  m_select_part_render = true;
}

void SelectCmd::remove_select_part(const entt::entity& e) {
  m_select_parts.erase(e);
  m_select_part_render = true;
}

void SelectCmd::remove_select_parts(const EntityArray& e_arr) {
  for (auto& e : e_arr) {
    m_select_parts.erase(e);
  }
  m_select_part_render = true;
}

void SelectCmd::clear_select_parts() {
  m_select_part_render = true;
  m_select_parts.clear();
}

void SelectCmd::clear_hover_parts() {
  m_hover_part_render = true;
  m_hover_parts.clear();
};

// 渲染接口
bool SelectCmd::select_render() {
  return m_select_render;
};
bool SelectCmd::hover_render() {
  return m_hover_render;
};
bool SelectCmd::select_part_render() {
  return m_select_part_render;
};
bool SelectCmd::hover_part_render() {
  return m_hover_part_render;
};

bool SelectCmd::algin_select_part_render() {
  return m_algin_select_part_render;
};
bool SelectCmd::algin_hover_part_render() {
  return m_algin_hover_part_render;
};

// 清除所有渲染
void SelectCmd::clear_render() {
  m_select_render = false;
  m_hover_render = false;
  m_select_part_render = false;
  m_hover_part_render = false;
  m_algin_select_part_render = false;
  m_algin_hover_part_render = false;
};

void SelectCmd::set_mouse_range(double r) {
  range = r;
};

}  // namespace qbe::select